
#include "wsaroutine.h"
#include "selector.h"
#include "sockexcept.h"
#include "raw_socket_impl.h"

using namespace sock;

struct Selector::Impl {

	fd_set read_set;
	fd_set write_set;
	fd_set error_set;

	fd_set read_set_last;
	fd_set write_set_last;
	fd_set error_set_last;

	Impl()
	{
		WsaRoutine::instance();
		clear_helper();
	}

	void clear_helper()
	{
		FD_ZERO( &read_set );
		FD_ZERO( &write_set );
		FD_ZERO( &error_set );
	}

	int select_helper( struct timeval * timeout )
	{
		read_set_last = read_set;
		write_set_last = write_set;
		error_set_last = error_set;	

		int res = ::select( 0, &read_set_last, &write_set_last, &error_set_last, timeout );
		if( res == SOCKET_ERROR ){
			throw SocketError( WSAGetLastError() );
		}
		return res;
	}

};


void Selector::clear()
{
	_pimpl->clear_helper();
}

void Selector::erase(sock::RawSocket &sock)
{
	FD_CLR( sock._pimpl->sock, &_pimpl->read_set );
}

bool Selector::isset(sock::RawSocket &sock)
{
	return FD_ISSET( sock._pimpl->sock, &_pimpl->read_set_last );
}

void Selector::set(sock::RawSocket &sock)
{
	FD_SET( sock._pimpl->sock, &_pimpl->read_set );
}

int Selector::select(time_t timeout)
{
	struct timeval timeout_struct;
	timeout_struct.tv_sec = timeout;
	timeout_struct.tv_usec = 0;

	return _pimpl->select_helper( &timeout_struct );
}

int Selector::select()
{
	return _pimpl->select_helper( NULL );	
}

Selector::Selector() : _pimpl( new Impl )
{

}

Selector::~Selector()
{
	delete _pimpl;
}